﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Thinker.SignChannel.Entities;
using Thinker.SignChannel.Repositories;
using Thinker.SignChannel.Results;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Volo.Abp.Uow;

namespace Thinker.SignChannel.Records;

public class RecordManager(
    IAsyncQueryableExecuter asyncExecuter,
    IRecordRepository recordRepository,
    IPersonRepository personRepository,
    IPersonTimeRepository personTimeRepository,
    ITimeRepository timeRepository) : ITransientDependency
{
    [UnitOfWork]
    public async Task<RecordInfo> AddAsync(string idNumber, string name)
    {
        var recordTime = DateTime.Now;
        var record = new Record(idNumber: idNumber, recordTime: recordTime, id: Guid.NewGuid());
        record.PersonName = name;

        var person = await personRepository.FindByKeyAsync(idNumber);
        record.PersonId = person?.Id;

        var time = await timeRepository.FindByTimeAsync(recordTime);
        record.TimeId = time?.Id;

        await recordRepository.InsertAsync(record, true);

        var recordInfo = new RecordInfo(record, person, time);
        return recordInfo;
    }

    public async Task<RecordInfo> GetAsync(Guid id)
    {
        var record = await recordRepository.GetAsync(id);
        return await GetAsync(record);
    }

    public async Task<RecordInfo> GetAsync(Record record)
    {
        Person? person = null;
        Time? time = null;
        if (record.PersonId != null)
        {
            person = await personRepository.GetAsync(record.PersonId.Value);
        }

        if (record.TimeId != null)
        {
            time = await timeRepository.GetAsync(record.TimeId.Value);
        }

        return new RecordInfo(record, person, time);
    }

    public async Task<int> CountSignedAsync(Guid timeId)
    {
        var query = await recordRepository.GetQueryableAsync();
        query = query.Where(x => x.TimeId == timeId && x.PersonId != null);
        var persons = query.Select(e => e.PersonId).Distinct();
        return await asyncExecuter.CountAsync(persons);
    }

    public async Task<int> CountTotalAsync(Guid timeId)
    {
        var people = await personRepository.CountAsync();

        var personTime = await personTimeRepository.CountAsync(x =>
            x.TimeId == timeId &&
            x.SignResult == SignResult.Leave);

        return people - personTime;
    }
}